// Copyright(c) 2011 Matthew McMullan, Jorel Lalicki and Mike Heise, Jorel Lalicki and Mike Heise. See copying.txt for details.

#ifndef __agml_vstatic_h__
#define __agml_vstatic_h__

// make sure that this file is never included directly
#ifndef __agml_agml_h__
#error "Include AGML from agml.h only. This file is not a valid entry point for the library."
#endif

#include <cmath>	// fixme

namespace agml {

template<typename t, u32 Size> struct vstatic {
	union {
		t data[Size];
		_v128 simd[(Size+sizeof(t)-1)/(16/sizeof(t))];
	};
	vstatic() {}
	vstatic(t o) {
		for (u32 i = 0; i<Size; ++i) {
			data[i] = o;
		}
	}
	vstatic(const vstatic &o) {
		for (u32 i = 0; i<Size; ++i) {
			data[i] = o.data[i];
		}
	}
	super_inline t& operator[](u32_fast element) {
		return data[element];
	}
	super_inline const t& operator[](u32_fast element) const {
		return data[element];
	}
	u32 size() {
		return Size;
	}
	u32 length() {
		return Size;
	}
	super_inline t dot(const vstatic &o) const {
		t tmp = 0;
		for (u32 i=0; i<Size; ++i) {
			tmp += data[i]*o.data[i];
		}
		return tmp;
	}
	super_inline f32 norm() const {
		t tmp = 0;
		for (u32 i=0; i<Size; ++i) {
			tmp += data[i]*data[i];
		}
		return sqrt((f32)tmp);
	}
	super_inline t sum() const {
		t tmp = 0;
		for (u32 i=0; i<Size; ++i) {
			tmp += data[i];
		}
		return tmp;
	}
	super_inline vstatic& operator=(const vstatic &o) {
		for (u32 i = 0; i<Size; ++i) {
			data[i] = o.data[i];
		}
		return *this;
	}
	void super_inline swap(vstatic &o) {
		for (u32 i = 0; i<Size; ++i) {
			swap(data[i],o.data[i]);
		}
		return *this;
	}
	super_inline vstatic& operator+=(const vstatic &o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]+=o.data[i];
		}
		return *this;
	}
	super_inline vstatic& operator+=(const t o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]+=o;
		}
		return *this;
	}
	super_inline vstatic& operator-=(const vstatic &o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]-=o.data[i];
		}
		return *this;
	}
	super_inline vstatic& operator-=(const t o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]-=o;
		}
		return *this;
	}
	super_inline vstatic& operator*=(const vstatic &o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]*=o.data[i];
		}
		return *this;
	}
	super_inline vstatic& operator*=(const t o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]*=o;
		}
		return *this;
	}
	super_inline vstatic& operator/=(const vstatic &o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]/=o.data[i];
		}
		return *this;
	}
	super_inline vstatic& operator/=(const t o) {
		for (u32 i = 0; i < Size; ++i) {
			data[i]/=o;
		}
		return *this;
	}
	super_inline vstatic operator+(const vstatic &o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] + o.data[i];
		}
		return tmp;
	}
	super_inline vstatic operator+(const t o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] + o;
		}
		return tmp;
	}
	super_inline vstatic operator-(const vstatic &o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] - o.data[i];
		}
		return tmp;
	}
	super_inline vstatic operator-(const t o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] - o;
		}
		return tmp;
	}
	super_inline vstatic operator*(const vstatic &o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] * o.data[i];
		}
		return tmp;
	}
	super_inline vstatic operator*(const t o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] * o;
		}
		return tmp;
	}
	super_inline vstatic operator/(const vstatic &o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] / o.data[i];
		}
		return tmp;
	}
	super_inline vstatic operator/(const t o) const {
		vstatic tmp;
		for (u32 i = 0; i < Size; ++i) {
			tmp.data[i] = data[i] / o;
		}
		return tmp;
	}

	bool super_inline operator==(const vstatic &o) const {
		for (u32 i=0; i<Size; ++i) {
			if (data[i] != o.data[i]) return false;
		}
		return true;
	}

	bool super_inline operator!=(const vstatic &o) const {
		return !(*this == o);
	}
};

}

#endif
